iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
自我挑戰組

Lex & Yacc 學習筆記系列 第 28

[Day28] Yacc - Command Line輸入

  • 分享至 

  • xImage
  •  

本篇內容

  • 如何將 terminal input 導入 parser
  • 範例:即時計算機

介紹

我們在之前所有的範例中,都是把文本寫在檔案內,再由 parser 讀取之。這次我們直接在 terminal 輸入字串組,讓 parser 根據我們所輸入的內容做計算。

範例 - 即時計算機

說明

請實作出一個簡易的計算機,根據 terminal 輸入的內容做計算,並將答案顯示在 terminal 上。使用者可以輸入多條算式,或輸入 “exit” 結束程式。

程式實作

  • Lex 實作
    • 定義 exit - 直接回傳0結束程式
  • Yacc 實作
    • 定義輸入規則(命名為 line) 採用 recursion 以不斷接收 input
  • Main 實作
    • 印出輸入提示字樣

完整程式碼

Lex

%{
#include "main.h"
#include "yacc.tab.h"
%}

integer     ([0-9]+)
float       ([0-9]*\.?[0-9]+)
blank_chars ([ \f\r\t\v]+)
expressions ([-+*/()])

%%

{integer}       { sscanf(yytext, "%d", &(yylval.intNum)); return INTEGER; }
{float}         { sscanf(yytext, "%f", &(yylval.floatNum)); return FLOAT; }
{expressions}   { return yytext[0]; }
{blank_chars}   { ; }
"="             { return yytext[0]; }
\n              { return yytext[0]; }
"exit"          { return 0; }

%%

int yywrap(void) {
    return 1;
}

Yacc

%{
#include "main.h"

void yyerror(const char *s);
extern int yylex();

%}

%union {
    float   floatNum;
    int     intNum;
}

%token <intNum>   INTEGER
%token <floatNum> FLOAT

%type <floatNum> value expr

%left '+' '-'
%left '*' '/'
%nonassoc UMINUS

%%

lines:
    | lines expr '\n'       { printf("Result: %f\n", $2); printf("Please insert an equation, or \"exit\" for exit.\n");}
    ;

expr:
      value                 { $$ = $1; }
    | expr '+' expr         { $$ = $1 + $3; }
    | expr '-' expr         { $$ = $1 - $3; }
    | expr '*' expr         { $$ = $1 * $3; }
    | expr '/' expr         
        { 
            if ($3 == 0.0) { 
                yyerror("Error: divisor cannot be zero!"); 
                YYABORT; 
            } else { 
                $$ = $1 / $3; 
            } 
        }
    | '-' expr %prec UMINUS { $$ = -$2; }
    | '(' expr ')'          { $$ = $2; }
    ;

value:
      FLOAT                 { $$ = $1; }
    | INTEGER               { $$ = (float)$1; }
    ;

%%

void yyerror(const char *s) {
    cerr << s << endl;
}

Main

  • main.h
#ifndef MAIN_H
#define MAIN_H

#include <iostream>
#include <stdio.h>

using namespace std;

#define YYSTYPE int
#endif
  • main.cpp
#include "main.h"
#include "yacc.tab.h"

extern int yyparse(void);

int main()
{
    printf("Please insert an equation, or \"exit\" for exit.\n");
    yyparse();
    return 0;
}

結語

基本上來說,許多應用程式的 commaand line 都是用 Lex & Yacc 的架構去執行的,因此這個範例可以延伸到許多非常複雜的系統,原理大致是相同的。

參考資料

  • Levine, John R., Tony Mason and Doug Brown [1992]. Lex & Yacc. O’Reilly & Associates, Inc. Sebastopol, California.
  • Tom Niemann. Lex & Yacc

上一篇
[Day27] Yacc 進階 - 使用外部變數
下一篇
[Day29] Yacc - Yacc Debug
系列文
Lex & Yacc 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言